#pragma once
#include <type_traits>
#include "Table.h"
namespace ese 
{
	class column
	{
	public:
		column(void) = delete;
		column(const column&) = delete;
		column(column&& c) = delete;
		column(table &tbl, const char *name, const JET_COLTYP columnType, const JET_GRBIT grbit = JET_bitColumnFixed, const unsigned long maxSize = 0);
		column(table &tbl, const char *name);

		~column() {}

		const JET_COLUMNID id(void) const { return m_cd.columnid; }
		const JET_ERR last_error(void) const { return m_last_error; }

		bool create(void);
		bool exists(void);

		bool set(const void *pData, const unsigned long cbData, JET_GRBIT grbit = 0, JET_SETINFO *Info = nullptr);
		bool set(const std::string& s) { return set(&s[0], static_cast<const unsigned long>(s.size())); }
		bool set(const std::wstring& s) { return set(&s[0], static_cast<const unsigned long>(s.size()) * sizeof(wchar_t)); }
		bool set(const std::vector<uint8_t>& v) { return set(&v[0], static_cast<const unsigned long>(v.size())); }
		template <class T> bool set(T t) 
		{
			static_assert(std::is_arithmetic<T>::value, "T must be arithmetic");
			return set(&t, sizeof(T)); 
		}

	private:
		void init();

		table &m_table;
		JET_COLUMNDEF m_cd;
		JET_ERR m_last_error;
		std::string m_name;
	};

	//============================================================================
	inline void column::init()
	{
		m_cd.cbStruct = sizeof(JET_COLUMNDEF);
		m_cd.columnid = 0;
		m_cd.coltyp = JET_coltypNil;
		m_cd.wCountry = 0;
		m_cd.langid = 0;
		m_cd.cp = 0;
		m_cd.wCollate = 0;
		m_cd.cbMax = 0;
		m_cd.grbit = 0;
	}

	inline column::column(table &tbl, const char *name, const JET_COLTYP columnType, const JET_GRBIT grbit, const unsigned long maxSize) : m_table(tbl)
		, m_name(name)
		, m_last_error(JET_errSuccess)
	{
		init();
		m_cd.coltyp = columnType;
		m_cd.grbit = grbit;
		m_cd.cbMax = maxSize;
	}


	inline column::column(table &tbl, const char *name) : m_table(tbl)
		, m_last_error(JET_errSuccess)
		, m_name(name)
	{
		init();
	}

	inline bool column::create(void)
	{
		JET_COLUMNID cid;
		m_last_error = ::JetAddColumnA(m_table.database().session().id(), m_table.id(), m_name.c_str(), &m_cd, nullptr, 0, &cid);
		if (JET_errSuccess == m_last_error)
		{
			m_cd.columnid = cid;
			return true;
		}// if
		return false;
	}

	inline bool column::exists(void)
	{
		return (JET_errSuccess == (m_last_error = JetGetColumnInfoA(m_table.database().session().id(), m_table.database().id(), m_table.name().c_str(), m_name.c_str(), &m_cd, sizeof(m_cd), JET_ColInfo)));
	}

	inline bool column::set(const void *pData, const unsigned long cbData, JET_GRBIT grbit, JET_SETINFO *info)
	{
		return (JET_errSuccess == (m_last_error = JetSetColumn(m_table.database().session().id()
			, m_table.id()
			, m_cd.columnid
			, pData, cbData
			, grbit
			, info)));
	}
}
